package cyx.example.ddd.application.order.command;

import cyx.example.ddd.application.order.assembler.OrderAssembler;
import cyx.example.ddd.application.order.dto.OrderDTO;
import cyx.example.ddd.domain.order.model.aggregate.Order;
import cyx.example.ddd.domain.order.model.valueobject.Money;
import cyx.example.ddd.domain.order.repository.OrderRepository;
import cyx.example.ddd.domain.order.service.OrderDomainService;
import cyx.example.ddd.domain.shared.DomainEvent;
import cyx.example.ddd.domain.shared.DomainEventPublisher;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.Valid;
import java.math.BigDecimal;
import java.util.List;

/**
 * 订单命令服务实现
 * 专门处理订单相关的写操作，实现CQRS模式
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class OrderCommandServiceImpl implements OrderCommandService {

    private final OrderDomainService orderDomainService;
    private final OrderRepository orderRepository;
    private final OrderAssembler orderAssembler;
    private final DomainEventPublisher eventPublisher;

    @Override
    @Transactional
    public OrderDTO createOrder(@Valid CreateOrderCommand command) {
        log.info("开始创建订单，用户ID: {}", command.getUserId());

        // 创建订单
        Order order = orderDomainService.createOrder(command.getUserId(), command.getCurrency());

        // 添加订单项
        command.getItems().forEach(item -> {
            Money unitPrice = new Money(BigDecimal.valueOf(item.getUnitPrice()), command.getCurrency());
            order.addOrderItem(item.getProductId(), item.getProductName(), unitPrice, item.getQuantity());
        });

        // 保存订单
        orderRepository.save(order);

        // 发布领域事件
        publishDomainEvents(order);

        log.info("订单创建成功，订单ID: {}", order.getId());

        // 转换为DTO返回
        return orderAssembler.toDTO(order);
    }

    @Override
    @Transactional
    public void payOrder(String orderId) {
        log.info("开始支付订单，订单ID: {}", orderId);

        orderRepository.findById(orderId)
                .ifPresent(order -> {
                    if (orderDomainService.validateOrderForPayment(order)) {
                        order.pay();
                        orderRepository.save(order);
                        publishDomainEvents(order);
                        log.info("订单支付成功，订单ID: {}", orderId);
                    } else {
                        log.warn("订单支付验证失败，订单ID: {}", orderId);
                        throw new IllegalStateException("Order is not valid for payment");
                    }
                });
    }

    @Override
    @Transactional
    public void cancelOrder(String orderId, String reason) {
        log.info("开始取消订单，订单ID: {}, 原因: {}", orderId, reason);

        orderRepository.findById(orderId)
                .ifPresent(order -> {
                    order.cancel(reason);
                    orderRepository.save(order);
                    publishDomainEvents(order);
                    log.info("订单取消成功，订单ID: {}", orderId);
                });
    }

    @Override
    @Transactional
    public void confirmOrder(String orderId) {
        log.info("开始确认订单，订单ID: {}", orderId);

        orderRepository.findById(orderId)
                .ifPresent(order -> {
                    order.confirm();
                    orderRepository.save(order);
                    publishDomainEvents(order);
                    log.info("订单确认成功，订单ID: {}", orderId);
                });
    }

    @Override
    @Transactional
    public void startShipping(String orderId) {
        log.info("开始配送订单，订单ID: {}", orderId);

        orderRepository.findById(orderId)
                .ifPresent(order -> {
                    order.startShipping();
                    orderRepository.save(order);
                    publishDomainEvents(order);
                    log.info("订单开始配送，订单ID: {}", orderId);
                });
    }

    @Override
    @Transactional
    public void completeOrder(String orderId) {
        log.info("开始完成订单，订单ID: {}", orderId);

        orderRepository.findById(orderId)
                .ifPresent(order -> {
                    order.complete();
                    orderRepository.save(order);
                    publishDomainEvents(order);
                    log.info("订单完成，订单ID: {}", orderId);
                });
    }

    /**
     * 发布聚合根中的所有领域事件
     * 
     * @param order 订单聚合根
     */
    private void publishDomainEvents(Order order) {
        List<DomainEvent> events = order.getDomainEvents();
        if (!events.isEmpty()) {
            log.info("发布 {} 个领域事件", events.size());
            events.forEach(event -> {
                log.debug("发布事件: {}", event.getEventType());
                eventPublisher.publish(event);
            });
            order.clearDomainEvents();
        }
    }
}